/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package Negocio;

import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author Ivan
 */
public abstract class MetodoBusqueda {

    protected TipoMetodo tipo;
    protected Estado estadoInicial;
    protected Estado estadoFinal;
    protected ArbolBusqueda arbol;

    public MetodoBusqueda(TipoMetodo tipo, Estado estadoInicial, Estado estadoFinal) {
        this.tipo = tipo;
        this.estadoInicial = estadoInicial;
        this.estadoFinal = estadoFinal;
    }

    public MetodoBusqueda() {
    }

    public ArbolBusqueda getArbol() {
        return arbol;
    }

    public void setArbol(ArbolBusqueda arbol) {
        this.arbol = arbol;
    }

    

    public Estado getEstadoFinal() {
        return estadoFinal;
    }

    public void setEstadoFinal(Estado estadoFinal) {
        this.estadoFinal = estadoFinal;
        this.estadoFinal.setEsFinal(true);
    }

    public Estado getEstadoInicial() {
        return estadoInicial;
    }

    public void setEstadoInicial(Estado estadoInicial) {
        this.estadoInicial = estadoInicial;
    }

    public TipoMetodo getTipo() {
        return tipo;
    }

    public void setTipo(TipoMetodo tipo) {
        this.tipo = tipo;
    }

    public List<Estado> obtenerEstados(Estado estado){
        ArrayList<Estado> estados=new ArrayList<Estado>();
        int fila=estado.getFila_vacio();
        int columna=estado.getColumna_vacio();
        int[][] temp=estado.getMatriz();
      


        int[][] estados_temp=new int[temp.length][temp[0].length];
        copiarMatrizEstado(estados_temp, temp);

            
        //Situacion 1;
        try{
            int valor=estados_temp[fila][columna-1];
            estados_temp[fila][columna]=valor;
            estados_temp[fila][columna-1]=Estado.getVacio();
            Estado nuevo=new Estado();
            nuevo.setFila_vacio(fila);
            nuevo.setColumna_vacio(columna-1);
            nuevo.setMatriz(copiarMatriz(estados_temp));
            estados.add(nuevo);

        }catch(Exception e){};

        //Situacion 2;
        copiarMatrizEstado(estados_temp, temp);
        try{
            int valor=estados_temp[fila][columna+1];
            estados_temp[fila][columna]=valor;
            estados_temp[fila][columna+1]=Estado.getVacio();
            Estado nuevo=new Estado();
            nuevo.setFila_vacio(fila);
            nuevo.setColumna_vacio(columna+1);
             nuevo.setMatriz( copiarMatriz(estados_temp));
            estados.add(nuevo);
        }catch(Exception e){};

        //Situacion 3;
        copiarMatrizEstado(estados_temp, temp);
        try{
            int valor=estados_temp[fila-1][columna];
            estados_temp[fila][columna]=valor;
            estados_temp[fila-1][columna]=Estado.getVacio();
            Estado nuevo=new Estado();
            nuevo.setFila_vacio(fila-1);
            nuevo.setColumna_vacio(columna);
            nuevo.setMatriz(copiarMatriz(estados_temp));
            estados.add(nuevo);

        }catch(Exception e){};

        //Situacion 4;
        copiarMatrizEstado(estados_temp, temp);
        try{
            int valor=estados_temp[fila+1][columna];
            estados_temp[fila][columna]=valor;
            estados_temp[fila+1][columna]=Estado.getVacio();
            Estado nuevo=new Estado();
            nuevo.setFila_vacio(fila+1);
            nuevo.setColumna_vacio(columna);
             nuevo.setMatriz(copiarMatriz(estados_temp));
            estados.add(nuevo);

        }catch(Exception e){};       

        return estados;
    }
    public abstract  List<Estado> obtenerOptimo();


    private void copiarMatrizEstado(int[][] matriz1, int[][] matriz2){

        for(int i=0;i < matriz2.length;i++){
            System.arraycopy(matriz2[i], 0, matriz1[i], 0, matriz2[0].length);
        }
        
    }

    private int[][] copiarMatriz(int[][] matriz){
        int[][] temp=new int[matriz.length][matriz[0].length];
        copiarMatrizEstado(temp, matriz);
        return temp;
    }

    public abstract void procesar();

    public void obtenerMetrica(Hoja estado){
        estado.obtenerFinal(estadoFinal);
    }

    public void cargarArbol(int niveles){
        arbol=new ArbolBusqueda();
        arbol.setNiveles(niveles);
        arbol.setMetodo(this);
        arbol.generarArbol();

    }
    public List<Estado> resolucionAutomatica(){
         List<Estado> optimo=new ArrayList<Estado>();
        Hoja temp=arbol.getCaminoOptimo().get(arbol.getCaminoOptimo().size()-1);

        optimo.add(0,temp.getEstado());

       while(temp.getPadre()!=null){
           temp=temp.getPadre();
           optimo.add(0,temp.getEstado());
    }
        return optimo;
    }

    public void iniciarArbol(){
        arbol=new ArbolBusqueda();
        arbol.setMetodo(this);
        arbol.inicializarArbol();
    }
}